﻿/************************************************************************************
 * xujiajun@yoozoo.com 御剑
 * 基于格子保存碰撞数据，每个格子保存着涵盖到该格子的圆
 * 碰撞检测时，先取出要碰撞的区域的格子，再取出格子里的所有圆进行精确判断
 * 当发生碰撞是IsHit将返回碰撞数据的ID，否则返回null
 ***********************************************************************************/

using System.Collections.Generic;

namespace WorldMapBase.Collision
{
    /// <summary>
    /// 基于格子保存碰撞数据，每个格子保存着涵盖到该格子的圆
    /// 碰撞检测时，先取出要碰撞的区域的格子，再取出格子里的所有圆进行精确判断
    /// 当发生碰撞是IsHit将返回碰撞数据的ID，否则返回null
    /// </summary>
    public class CircleSetsCollisionData : CircleCollisionData<HashSet<string>>
    {
        /// <summary>
        /// 2D圆的辅助数据结构
        /// </summary>
        private struct Circle
        {
            /// <summary>
            /// 横坐标
            /// </summary>
            public float x;

            /// <summary>
            /// 纵坐标
            /// </summary>
            public float y;

            /// <summary>
            /// 半径
            /// </summary>
            public float r;
        }

        /// <summary>
        /// 碰撞ID与圆的映射
        /// </summary>
        private Dictionary<string, Circle> m_CircleDic;

        /// <summary>
        /// 防止创建局部变量所创建的集合
        /// </summary>
        private HashSet<string> m_TmpSet;

        public CircleSetsCollisionData(int gridSize) : base(gridSize)
        {
            m_CircleDic = new Dictionary<string, Circle>();
            m_TmpSet = new HashSet<string>();
        }

        /// <summary>
        /// 移除指定ID的碰撞区域
        /// </summary>
        /// <param name="id"></param>
        public void RemoveCollision(string id)
        {
            if (m_CircleDic.ContainsKey(id))
            {
                var circle = m_CircleDic[id];
                RemoveCollision(id, circle.x, circle.y, circle.r);
            }
        }

        protected override HashSet<string> OnNewData()
        {
            return new HashSet<string>();
        }

        protected override HashSet<string> OnAddData(string id, HashSet<string> t)
        {
            t.Add(id);
            return t;
        }

        protected override HashSet<string> OnRemoveData(string id, HashSet<string> t)
        {
            t.Remove(id);
            return t;
        }

        protected override string OnIsHit(float x, float y, float r, List<HashSet<string>> list)
        {
            m_TmpSet.Clear();
            foreach (var set in list)
            {
                foreach (var v in set)
                {
                    m_TmpSet.Add(v);
                }
            }

            foreach (var v in m_TmpSet)
            {
                var circle = m_CircleDic[v];
                var deltaX = circle.x - x;
                var deltaY = circle.y - y;
                var totalR = r + circle.r;
                var sqDis = deltaX * deltaX + deltaY * deltaY;
                var sqR = totalR * totalR;
                if (sqR > sqDis)
                {
                    return v;
                }

            }
            return null;
        }

        protected override void OnClear()
        {
            m_CircleDic.Clear();
        }

        protected override void OnAddDataFinish(string id, float x, float y, float r)
        {
            m_CircleDic.Add(id, new Circle() { x = x, y = y, r = r });
        }

        protected override void OnRemoveDataFinish(string id, float x, float y, float r)
        {
            m_CircleDic.Remove(id);
        }
    }

}
